home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / WarpQuake / Src / sys_dos.c < prev    next >
C/C++ Source or Header  |  2000-05-22  |  21KB  |  954 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. #include <errno.h>
  21. #include <unistd.h>
  22. #include <signal.h>
  23. #include <stdlib.h>
  24. #include <limits.h>
  25. #include <sys/time.h>
  26. #include <sys/types.h>
  27. #include <dir.h>
  28. #include <unistd.h>
  29. #include <fcntl.h>
  30. #include <stdarg.h>
  31. #include <stdio.h>
  32. #include <sys/stat.h>
  33. #include <string.h>
  34. #include <dpmi.h>
  35. #include <sys/nearptr.h>
  36. #include <conio.h>
  37.  
  38. #include "quakedef.h"
  39. #include "dosisms.h"
  40.  
  41. #define MINIMUM_WIN_MEMORY            0x800000
  42. #define MINIMUM_WIN_MEMORY_LEVELPAK    (MINIMUM_WIN_MEMORY + 0x100000)
  43.  
  44. int            end_of_memory;
  45. qboolean    lockmem, lockunlockmem, unlockmem;
  46. static int    win95;
  47.  
  48. #define STDOUT    1
  49.  
  50. #define    KEYBUF_SIZE    256
  51. static unsigned char    keybuf[KEYBUF_SIZE];
  52. static int                keybuf_head=0;
  53. static int                keybuf_tail=0;
  54.  
  55. static quakeparms_t    quakeparms;
  56. int                    sys_checksum;
  57. static double        curtime = 0.0;
  58. static double        lastcurtime = 0.0;
  59. static double        oldtime = 0.0;
  60.  
  61. static qboolean        isDedicated;
  62.  
  63. static int            minmem;
  64.  
  65. float                fptest_temp;
  66.  
  67. extern char    start_of_memory __asm__("start");
  68.  
  69. //=============================================================================
  70.  
  71. // this is totally dependent on cwsdpmi putting the stack right after tge
  72. // global data
  73.  
  74. // This does evil things in a Win95 DOS box!!!
  75. #if 0
  76. extern byte end;
  77. #define    CHECKBYTE    0xed
  78. void Sys_InitStackCheck (void)
  79. {
  80.     int        i;
  81.     
  82.     for (i=0 ; i<128*1024 ; i++)
  83.         (&end)[i] = CHECKBYTE;
  84. }
  85.  
  86. void Sys_StackCheck (void)
  87. {
  88.     int        i;
  89.     
  90.     for (i=0 ; i<128*1024 ; i++)
  91.         if ( (&end)[i] != CHECKBYTE )
  92.             break;
  93.     
  94.     Con_Printf ("%i undisturbed stack bytes\n", i);
  95.     if (end != CHECKBYTE)
  96.         Sys_Error ("System stack overflow!");
  97. }
  98. #endif
  99.  
  100. //=============================================================================
  101.  
  102. byte        scantokey[128] = 
  103.                     { 
  104. //  0           1       2       3       4       5       6       7 
  105. //  8           9       A       B       C       D       E       F 
  106.     0  ,    27,     '1',    '2',    '3',    '4',    '5',    '6', 
  107.     '7',    '8',    '9',    '0',    '-',    '=',    K_BACKSPACE, 9, // 0 
  108.     'q',    'w',    'e',    'r',    't',    'y',    'u',    'i', 
  109.     'o',    'p',    '[',    ']',    13 ,    K_CTRL,'a',  's',      // 1 
  110.     'd',    'f',    'g',    'h',    'j',    'k',    'l',    ';', 
  111.     '\'' ,    '`',    K_SHIFT,'\\',  'z',    'x',    'c',    'v',      // 2 
  112.     'b',    'n',    'm',    ',',    '.',    '/',    K_SHIFT,'*', 
  113.     K_ALT,' ',   0  ,    K_F1, K_F2, K_F3, K_F4, K_F5,   // 3 
  114.     K_F6, K_F7, K_F8, K_F9, K_F10,0  ,    0  , K_HOME, 
  115.     K_UPARROW,K_PGUP,'-',K_LEFTARROW,'5',K_RIGHTARROW,'+',K_END, //4 
  116.     K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0,             0,              K_F11, 
  117.     K_F12,0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 5 
  118.     0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0, 
  119.     0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 6 
  120.     0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0, 
  121.     0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0         // 7 
  122.                     }; 
  123.  
  124. byte        shiftscantokey[128] = 
  125.                     { 
  126. //  0           1       2       3       4       5       6       7 
  127. //  8           9       A       B       C       D       E       F 
  128.     0  ,    27,     '!',    '@',    '#',    '$',    '%',    '^', 
  129.     '&',    '*',    '(',    ')',    '_',    '+',    K_BACKSPACE, 9, // 0 
  130.     'Q',    'W',    'E',    'R',    'T',    'Y',    'U',    'I', 
  131.     'O',    'P',    '{',    '}',    13 ,    K_CTRL,'A',  'S',      // 1 
  132.     'D',    'F',    'G',    'H',    'J',    'K',    'L',    ':', 
  133.     '"' ,    '~',    K_SHIFT,'|',  'Z',    'X',    'C',    'V',      // 2 
  134.     'B',    'N',    'M',    '<',    '>',    '?',    K_SHIFT,'*', 
  135.     K_ALT,' ',   0  ,    K_F1, K_F2, K_F3, K_F4, K_F5,   // 3 
  136.     K_F6, K_F7, K_F8, K_F9, K_F10,0  ,    0  , K_HOME, 
  137.     K_UPARROW,K_PGUP,'_',K_LEFTARROW,'%',K_RIGHTARROW,'+',K_END, //4 
  138.     K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0,             0,              K_F11, 
  139.     K_F12,0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 5 
  140.     0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0, 
  141.     0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 6 
  142.     0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0, 
  143.     0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0         // 7 
  144.                     }; 
  145.  
  146. void TrapKey(void)
  147. {
  148. //    static int ctrl=0;
  149.     keybuf[keybuf_head] = dos_inportb(0x60);
  150.     dos_outportb(0x20, 0x20);
  151.     /*
  152.     if (scantokey[keybuf[keybuf_head]&0x7f] == K_CTRL)
  153.         ctrl=keybuf[keybuf_head]&0x80;
  154.     if (ctrl && scantokey[keybuf[keybuf_head]&0x7f] == 'c')
  155.         Sys_Error("ctrl-c hit\n");
  156.     */
  157.     keybuf_head = (keybuf_head + 1) & (KEYBUF_SIZE-1);
  158. }
  159.  
  160. #define SC_UPARROW              0x48
  161. #define SC_DOWNARROW    0x50
  162. #define SC_LEFTARROW            0x4b
  163. #define SC_RIGHTARROW   0x4d
  164. #define SC_LEFTSHIFT   0x2a
  165. #define SC_RIGHTSHIFT   0x36
  166. #define SC_RIGHTARROW   0x4d
  167.  
  168. void MaskExceptions (void);
  169. void Sys_InitFloatTime (void);
  170. void Sys_PushFPCW_SetHigh (void);
  171. void Sys_PopFPCW (void);
  172.  
  173. #define LEAVE_FOR_CACHE (512*1024)        //FIXME: tune
  174. #define LOCKED_FOR_MALLOC (128*1024)    //FIXME: tune
  175.  
  176.  
  177. void Sys_DetectWin95 (void)
  178. {
  179.     __dpmi_regs                r;
  180.  
  181.     r.x.ax = 0x160a;        /* Get Windows Version */
  182.     __dpmi_int(0x2f, &r);
  183.  
  184.     if(r.x.ax || r.h.bh < 4)    /* Not windows or earlier than Win95 */
  185.     {
  186.         win95 = 0;
  187.         lockmem = true;
  188.         lockunlockmem = false;
  189.         unlockmem = true;
  190.     }
  191.     else
  192.     {
  193.         win95 = 1;
  194.         lockunlockmem = COM_CheckParm ("-winlockunlock");
  195.  
  196.         if (lockunlockmem)
  197.             lockmem = true;
  198.         else
  199.             lockmem = COM_CheckParm ("-winlock");
  200.  
  201.         unlockmem = lockmem && !lockunlockmem;
  202.     }
  203. }
  204.  
  205.  
  206. void *dos_getmaxlockedmem(int *size)
  207. {
  208.     __dpmi_free_mem_info    meminfo;
  209.     __dpmi_meminfo            info;
  210.     int                        working_size;
  211.     void                    *working_memory;
  212.     int                        last_locked;
  213.     int                        extra,     i, j, allocsize;
  214.     static char                *msg = "Locking data...";
  215.     int                        m, n;
  216.     byte                    *x;
  217.  
  218. // first lock all the current executing image so the locked count will
  219. // be accurate.  It doesn't hurt to lock the memory multiple times
  220.     last_locked = __djgpp_selector_limit + 1;
  221.     info.size = last_locked - 4096;
  222.     info.address = __djgpp_base_address + 4096;
  223.  
  224.     if (lockmem)
  225.     {
  226.         if(__dpmi_lock_linear_region(&info))
  227.         {
  228.             Sys_Error ("Lock of current memory at 0x%lx for %ldKb failed!\n",
  229.                         info.address, info.size/1024);
  230.         }
  231.     }
  232.  
  233.     __dpmi_get_free_memory_information(&meminfo);
  234.  
  235.     if (!win95)        /* Not windows or earlier than Win95 */
  236.     {
  237.         working_size = meminfo.maximum_locked_page_allocation_in_pages * 4096;
  238.     }
  239.     else
  240.     {
  241.         working_size = meminfo.largest_available_free_block_in_bytes -
  242.                 LEAVE_FOR_CACHE;
  243.     }
  244.  
  245.     working_size &= ~0xffff;        /* Round down to 64K */
  246.     working_size += 0x10000;
  247.  
  248.     do
  249.     {
  250.         working_size -= 0x10000;        /* Decrease 64K and try again */
  251.         working_memory = sbrk(working_size);
  252.     } while (working_memory == (void *)-1);
  253.  
  254.     extra = 0xfffc - ((unsigned)sbrk(0) & 0xffff);
  255.  
  256.     if (extra > 0)
  257.     {
  258.         sbrk(extra);
  259.         working_size += extra;
  260.     }
  261.  
  262. // now grab the memory
  263.     info.address = last_locked + __djgpp_base_address;
  264.  
  265.     if (!win95)
  266.     {
  267.         info.size = __djgpp_selector_limit + 1 - last_locked;
  268.  
  269.         while (info.size > 0 && __dpmi_lock_linear_region(&info))
  270.         {
  271.             info.size -= 0x1000;
  272.             working_size -= 0x1000;
  273.             sbrk(-0x1000);
  274.         }
  275.     }
  276.     else
  277.     {            /* Win95 section */
  278.         j = COM_CheckParm("-winmem");
  279.  
  280.         if (standard_quake)
  281.             minmem = MINIMUM_WIN_MEMORY;
  282.         else
  283.             minmem = MINIMUM_WIN_MEMORY_LEVELPAK;
  284.  
  285.         if (j)
  286.         {
  287.             allocsize = ((int)(Q_atoi(com_argv[j+1]))) * 0x100000 +
  288.                     LOCKED_FOR_MALLOC;
  289.  
  290.             if (allocsize < (minmem + LOCKED_FOR_MALLOC))
  291.                 allocsize = minmem + LOCKED_FOR_MALLOC;
  292.         }
  293.         else
  294.         {
  295.             allocsize = minmem + LOCKED_FOR_MALLOC;
  296.         }
  297.  
  298.         if (!lockmem)
  299.         {
  300.         // we won't lock, just sbrk the memory
  301.             info.size = allocsize;
  302.             goto UpdateSbrk;
  303.         }
  304.  
  305.         // lock the memory down
  306.         write (STDOUT, msg, strlen (msg));
  307.  
  308.         for (j=allocsize ; j>(minmem + LOCKED_FOR_MALLOC) ;
  309.              j -= 0x100000)
  310.         {
  311.             info.size = j;
  312.     
  313.             if (!__dpmi_lock_linear_region(&info))
  314.                 goto Locked;
  315.     
  316.             write (STDOUT, ".", 1);
  317.         }
  318.  
  319.     // finally, try with the absolute minimum amount
  320.         for (i=0 ; i<10 ; i++)
  321.         {
  322.             info.size = minmem + LOCKED_FOR_MALLOC;
  323.  
  324.             if (!__dpmi_lock_linear_region(&info))
  325.                 goto Locked;
  326.         }
  327.  
  328.         Sys_Error ("Can't lock memory; %d Mb lockable RAM required. "
  329.                    "Try shrinking smartdrv.", info.size / 0x100000);
  330.  
  331. Locked:
  332.  
  333. UpdateSbrk:
  334.  
  335.         info.address += info.size;
  336.         info.address -= __djgpp_base_address + 4; // ending point, malloc align
  337.         working_size = info.address - (int)working_memory;
  338.         sbrk(info.address-(int)sbrk(0));        // negative adjustment
  339.     }
  340.  
  341.  
  342.     if (lockunlockmem)
  343.     {
  344.         __dpmi_unlock_linear_region (&info);
  345.         printf ("Locked and unlocked %d Mb data\n", working_size / 0x100000);
  346.     }
  347.     else if (lockmem)
  348.     {
  349.         printf ("Locked %d Mb data\n", working_size / 0x100000);
  350.     }
  351.     else
  352.     {
  353.         printf ("Allocated %d Mb data\n", working_size / 0x100000);
  354.     }
  355.  
  356. // touch all the memory to make sure it's there. The 16-page skip is to
  357. // keep Win 95 from thinking we're trying to page ourselves in (we are
  358. // doing that, of course, but there's no reason we shouldn't)
  359.     x = (byte *)working_memory;
  360.  
  361.     for (n=0 ; n<4 ; n++)
  362.     {
  363.         for (m=0 ; m<(working_size - 16 * 0x1000) ; m += 4)
  364.         {
  365.             sys_checksum += *(int *)&x[m];
  366.             sys_checksum += *(int *)&x[m + 16 * 0x1000];
  367.         }
  368.     }
  369.  
  370. // give some of what we locked back for malloc before returning.  Done
  371. // by cheating and passing a negative value to sbrk
  372.     working_size -= LOCKED_FOR_MALLOC;
  373.     sbrk( -(LOCKED_FOR_MALLOC));
  374.     *size = working_size;
  375.     return working_memory;
  376. }
  377.  
  378.  
  379. /*
  380. ============
  381. Sys_FileTime
  382.  
  383. returns -1 if not present
  384. ============
  385. */
  386. int    Sys_FileTime (char *path)
  387. {
  388.     struct    stat    buf;
  389.     
  390.     if (stat (path,&buf) == -1)
  391.         return -1;
  392.     
  393.     return buf.st_mtime;
  394. }
  395.  
  396. void Sys_mkdir (char *path)
  397. {
  398.     mkdir (path, 0777);
  399. }
  400.  
  401.  
  402. void Sys_Sleep(void)
  403. {
  404. }
  405.  
  406.  
  407. char *Sys_ConsoleInput(void)
  408. {
  409.     static char    text[256];
  410.     static int    len = 0;
  411.     char        ch;
  412.  
  413.     if (!isDedicated)
  414.         return NULL;
  415.  
  416.     if (! kbhit())
  417.         return NULL;
  418.  
  419.     ch = getche();
  420.  
  421.     switch (ch)
  422.     {
  423.         case '\r':
  424.             putch('\n');
  425.             if (len)
  426.             {
  427.                 text[len] = 0;
  428.                 len = 0;
  429.                 return text;
  430.             }
  431.             break;
  432.  
  433.         case '\b':
  434.             putch(' ');
  435.             if (len)
  436.             {
  437.                 len--;
  438.                 putch('\b');
  439.             }
  440.             break;
  441.  
  442.         default:
  443.             text[len] = ch;
  444.             len = (len + 1) & 0xff;
  445.             break;
  446.     }
  447.  
  448.     return NULL;
  449. }
  450.  
  451. void Sys_Init(void)
  452. {
  453.  
  454.     MaskExceptions ();
  455.  
  456.     Sys_SetFPCW ();
  457.  
  458.     dos_outportb(0x43, 0x34); // set system timer to mode 2
  459.     dos_outportb(0x40, 0);    // for the Sys_FloatTime() function
  460.     dos_outportb(0x40, 0);
  461.  
  462.     Sys_InitFloatTime ();
  463.  
  464.     _go32_interrupt_stack_size = 4 * 1024;;
  465.     _go32_rmcb_stack_size = 4 * 1024;
  466. }
  467.  
  468. void Sys_Shutdown(void)
  469. {
  470.     if (!isDedicated)
  471.         dos_restoreintr(9);
  472.  
  473.     if (unlockmem)
  474.     {
  475.         dos_unlockmem (&start_of_memory,
  476.                        end_of_memory - (int)&start_of_memory);
  477.         dos_unlockmem (quakeparms.membase, quakeparms.memsize);
  478.     }
  479. }
  480.  
  481.  
  482. #define SC_RSHIFT       0x36 
  483. #define SC_LSHIFT       0x2a 
  484. void Sys_SendKeyEvents (void)
  485. {
  486.     int k, next;
  487.     int outkey;
  488.  
  489. // get key events
  490.  
  491.     while (keybuf_head != keybuf_tail)
  492.     {
  493.  
  494.         k = keybuf[keybuf_tail++];
  495.         keybuf_tail &= (KEYBUF_SIZE-1);
  496.  
  497.         if (k==0xe0)
  498.             continue;               // special / pause keys
  499.         next = keybuf[(keybuf_tail-2)&(KEYBUF_SIZE-1)];
  500.         if (next == 0xe1)
  501.             continue;                               // pause key bullshit
  502.         if (k==0xc5 && next == 0x9d) 
  503.         { 
  504.             Key_Event (K_PAUSE, true);
  505.             continue; 
  506.         } 
  507.  
  508.         // extended keyboard shift key bullshit 
  509.         if ( (k&0x7f)==SC_LSHIFT || (k&0x7f)==SC_RSHIFT ) 
  510.         { 
  511.             if ( keybuf[(keybuf_tail-2)&(KEYBUF_SIZE-1)]==0xe0 ) 
  512.                 continue; 
  513.             k &= 0x80; 
  514.             k |= SC_RSHIFT; 
  515.         } 
  516.  
  517.         if (k==0xc5 && keybuf[(keybuf_tail-2)&(KEYBUF_SIZE-1)] == 0x9d)
  518.             continue; // more pause bullshit
  519.  
  520.         outkey = scantokey[k & 0x7f];
  521.  
  522.         if (k & 0x80)
  523.             Key_Event (outkey, false);
  524.         else
  525.             Key_Event (outkey, true);
  526.  
  527.     }
  528.  
  529. }
  530.  
  531.  
  532. // =======================================================================
  533. // General routines
  534. // =======================================================================
  535.  
  536. /*
  537. ================
  538. Sys_Printf
  539. ================
  540. */
  541.  
  542. void Sys_Printf (char *fmt, ...)
  543. {
  544.     va_list        argptr;
  545.     char        text[1024];
  546.     
  547.     va_start (argptr,fmt);
  548.     vsprintf (text,fmt,argptr);
  549.     va_end (argptr);
  550.  
  551.     if (cls.state == ca_dedicated)
  552.         fprintf(stderr, "%s", text);
  553. }
  554.  
  555. void Sys_AtExit (void)
  556. {
  557.  
  558. // shutdown only once (so Sys_Error can call this function to shutdown, then
  559. // print the error message, then call exit without exit calling this function
  560. // again)
  561.     Sys_Shutdown();
  562. }
  563.  
  564.  
  565. void Sys_Quit (void)
  566. {
  567.     byte    screen[80*25*2];
  568.     byte    *d;
  569.     char            ver[6];
  570.     int            i;
  571.     
  572.  
  573. // load the sell screen before shuting everything down
  574.     if (registered.value)
  575.         d = COM_LoadHunkFile ("end2.bin"); 
  576.     else
  577.         d = COM_LoadHunkFile ("end1.bin"); 
  578.     if (d)
  579.         memcpy (screen, d, sizeof(screen));
  580.  
  581. // write the version number directly to the end screen
  582.     sprintf (ver, " v%4.2f", VERSION);
  583.     for (i=0 ; i<6 ; i++)
  584.         screen[0*80*2 + 72*2 + i*2] = ver[i];
  585.  
  586.     Host_Shutdown();
  587.  
  588. // do the text mode sell screen
  589.     if (d)
  590.     {
  591.         memcpy ((void *)real2ptr(0xb8000), screen,80*25*2); 
  592.     
  593.     // set text pos
  594.         regs.x.ax = 0x0200; 
  595.         regs.h.bh = 0; 
  596.         regs.h.dl = 0; 
  597.         regs.h.dh = 22;
  598.         dos_int86 (0x10); 
  599.     }
  600.     else
  601.         printf ("couldn't load endscreen.\n");
  602.  
  603.     exit(0);
  604. }
  605.  
  606. void Sys_Error (char *error, ...)
  607.     va_list     argptr;
  608.     char        string[1024];
  609.     
  610.     va_start (argptr,error);
  611.     vsprintf (string,error,argptr);
  612.     va_end (argptr);
  613.  
  614.     Host_Shutdown();
  615.     fprintf(stderr, "Error: %s\n", string);
  616. // Sys_AtExit is called by exit to shutdown the system
  617.     exit(0);
  618.  
  619.  
  620. int Sys_FileOpenRead (char *path, int *handle)
  621. {
  622.     int    h;
  623.     struct stat    fileinfo;
  624.     
  625.     h = open (path, O_RDONLY|O_BINARY, 0666);
  626.     *handle = h;
  627.     if (h == -1)
  628.         return -1;
  629.     
  630.     if (fstat (h,&fileinfo) == -1)
  631.         Sys_Error ("Error fstating %s", path);
  632.  
  633.     return fileinfo.st_size;
  634. }
  635.  
  636. int Sys_FileOpenWrite (char *path)
  637. {
  638.     int     handle;
  639.  
  640.     umask (0);
  641.     
  642.     handle = open(path,O_RDWR | O_BINARY | O_CREAT | O_TRUNC
  643.     , 0666);
  644.  
  645.     if (handle == -1)
  646.         Sys_Error ("Error opening %s: %s", path,strerror(errno));
  647.  
  648.     return handle;
  649. }
  650.  
  651. void Sys_FileClose (int handle)
  652. {
  653.     close (handle);
  654. }
  655.  
  656. void Sys_FileSeek (int handle, int position)
  657. {
  658.     lseek (handle, position, SEEK_SET);
  659. }
  660.  
  661. int Sys_FileRead (int handle, void *dest, int count)
  662. {
  663.    return read (handle, dest, count);
  664. }
  665.  
  666. int Sys_FileWrite (int handle, void *data, int count)
  667. {
  668.     return write (handle, data, count);
  669. }
  670.  
  671. /*
  672. ================
  673. Sys_MakeCodeWriteable
  674. ================
  675. */
  676. void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
  677. {
  678.     // it's always writeable
  679. }
  680.  
  681.  
  682. /*
  683. ================
  684. Sys_FloatTime
  685. ================
  686. */
  687. double Sys_FloatTime (void)
  688. {
  689.     int                r;
  690.     unsigned        t, tick;
  691.     double            ft, time;
  692.     static int        sametimecount;
  693.  
  694.     Sys_PushFPCW_SetHigh ();
  695.  
  696. //{static float t = 0; t=t+0.05; return t;}    // DEBUG
  697.  
  698.     t = *(unsigned short*)real2ptr(0x46c) * 65536;
  699.  
  700.     dos_outportb(0x43, 0); // latch time
  701.     r = dos_inportb(0x40);
  702.     r |= dos_inportb(0x40) << 8;
  703.     r = (r-1) & 0xffff;
  704.  
  705.     tick = *(unsigned short*)real2ptr(0x46c) * 65536;
  706.     if ((tick != t) && (r & 0x8000))
  707.         t = tick;
  708.  
  709.     ft = (double) (t+(65536-r)) / 1193200.0;
  710.     time = ft - oldtime;
  711.     oldtime = ft;
  712.  
  713.     if (time < 0)
  714.     {
  715.         if (time > -3000.0)
  716.             time = 0.0;
  717.         else
  718.             time += 3600.0;
  719.     }
  720.  
  721.     curtime += time;
  722.  
  723.     if (curtime == lastcurtime)
  724.     {
  725.         sametimecount++;
  726.  
  727.         if (sametimecount > 100000)
  728.         {
  729.             curtime += 1.0;
  730.             sametimecount = 0;
  731.         }
  732.     }
  733.     else
  734.     {
  735.         sametimecount = 0;
  736.     }
  737.  
  738.     lastcurtime = curtime;
  739.  
  740.     Sys_PopFPCW ();
  741.  
  742.     return curtime;
  743. }
  744.  
  745.  
  746. /*
  747. ================
  748. Sys_InitFloatTime
  749. ================
  750. */
  751. void Sys_InitFloatTime (void)
  752. {
  753.     int        j;
  754.  
  755.     Sys_FloatTime ();
  756.  
  757.     oldtime = curtime;
  758.  
  759.     j = COM_CheckParm("-starttime");
  760.  
  761.     if (j)
  762.     {
  763.         curtime = (double) (Q_atof(com_argv[j+1]));
  764.     }
  765.     else
  766.     {
  767.         curtime = 0.0;
  768.     }
  769.     lastcurtime = curtime;
  770. }
  771.  
  772.  
  773. /*
  774. ================
  775. Sys_GetMemory
  776. ================
  777. */
  778. void Sys_GetMemory(void)
  779. {
  780.     int        j, tsize;
  781.  
  782.     j = COM_CheckParm("-mem");
  783.     if (j)
  784.     {
  785.         quakeparms.memsize = (int) (Q_atof(com_argv[j+1]) * 1024 * 1024);
  786.         quakeparms.membase = malloc (quakeparms.memsize);
  787.     }
  788.     else
  789.     {
  790.         quakeparms.membase = dos_getmaxlockedmem (&quakeparms.memsize);
  791.     }
  792.  
  793.     fprintf(stderr, "malloc'd: %d\n", quakeparms.memsize);
  794.  
  795.     if (COM_CheckParm ("-heapsize"))
  796.     {
  797.         tsize = Q_atoi (com_argv[COM_CheckParm("-heapsize") + 1]) * 1024;
  798.  
  799.         if (tsize < quakeparms.memsize)
  800.             quakeparms.memsize = tsize;
  801.     }
  802. }
  803.  
  804.  
  805. /*
  806. ================
  807. Sys_PageInProgram
  808.  
  809. walks the text, data, and bss to make sure it's all paged in so that the
  810. actual physical memory detected by Sys_GetMemory is correct.
  811. ================
  812. */
  813. void Sys_PageInProgram(void)
  814. {
  815.     int        i, j;
  816.  
  817.     end_of_memory = (int)sbrk(0);
  818.  
  819.     if (lockmem)
  820.     {
  821.         if (dos_lockmem ((void *)&start_of_memory,
  822.                          end_of_memory - (int)&start_of_memory))
  823.             Sys_Error ("Couldn't lock text and data");
  824.     }
  825.  
  826.     if (lockunlockmem)
  827.     {
  828.         dos_unlockmem((void *)&start_of_memory,
  829.                          end_of_memory - (int)&start_of_memory);
  830.         printf ("Locked and unlocked %d Mb image\n",
  831.                 (end_of_memory - (int)&start_of_memory) / 0x100000);
  832.     }
  833.     else if (lockmem)
  834.     {
  835.         printf ("Locked %d Mb image\n",
  836.                 (end_of_memory - (int)&start_of_memory) / 0x100000);
  837.     }
  838.     else
  839.     {
  840.         printf ("Loaded %d Mb image\n",
  841.                 (end_of_memory - (int)&start_of_memory) / 0x100000);
  842.     }
  843.  
  844. // touch the entire image, doing the 16-page skip so Win95 doesn't think we're
  845. // trying to page ourselves in
  846.     for (j=0 ; j<4 ; j++)
  847.     {
  848.         for(i=(int)&start_of_memory ; i<(end_of_memory - 16 * 0x1000) ; i += 4)
  849.         {
  850.             sys_checksum += *(int *)i;
  851.             sys_checksum += *(int *)(i + 16 * 0x1000);
  852.         }
  853.     }
  854. }
  855.  
  856.  
  857. /*
  858. ================
  859. Sys_NoFPUExceptionHandler
  860. ================
  861. */
  862. void Sys_NoFPUExceptionHandler(int whatever)
  863. {
  864.     printf ("\nError: Quake requires a floating-point processor\n");
  865.     exit (0);
  866. }
  867.  
  868.  
  869. /*
  870. ================
  871. Sys_DefaultExceptionHandler
  872. ================
  873. */
  874. void Sys_DefaultExceptionHandler(int whatever)
  875. {
  876. }
  877.  
  878.  
  879. /*
  880. ================
  881. main
  882. ================
  883. */
  884. int main (int c, char **v)
  885. {
  886.     double            time, oldtime, newtime;
  887.     extern void (*dos_error_func)(char *, ...);
  888.     static    char    cwd[1024];
  889.  
  890.     printf ("Quake v%4.2f\n", VERSION);
  891.     
  892. // make sure there's an FPU
  893.     signal(SIGNOFP, Sys_NoFPUExceptionHandler);
  894.     signal(SIGABRT, Sys_DefaultExceptionHandler);
  895.     signal(SIGALRM, Sys_DefaultExceptionHandler);
  896.     signal(SIGKILL, Sys_DefaultExceptionHandler);
  897.     signal(SIGQUIT, Sys_DefaultExceptionHandler);
  898.     signal(SIGINT, Sys_DefaultExceptionHandler);
  899.  
  900.     if (fptest_temp >= 0.0)
  901.         fptest_temp += 0.1;
  902.  
  903.     COM_InitArgv (c, v);
  904.  
  905.     quakeparms.argc = com_argc;
  906.     quakeparms.argv = com_argv;
  907.  
  908.     dos_error_func = Sys_Error;
  909.  
  910.     Sys_DetectWin95 ();
  911.     Sys_PageInProgram ();
  912.     Sys_GetMemory ();
  913.  
  914.     atexit (Sys_AtExit);    // in case we crash
  915.  
  916.     getwd (cwd);
  917.     if (cwd[Q_strlen(cwd)-1] == '/') cwd[Q_strlen(cwd)-1] = 0;
  918.     quakeparms.basedir = cwd; //"f:/quake";
  919.  
  920.     isDedicated = (COM_CheckParm ("-dedicated") != 0);
  921.  
  922.     Sys_Init ();
  923.  
  924.     if (!isDedicated)
  925.         dos_registerintr(9, TrapKey);
  926.  
  927. //Sys_InitStackCheck ();
  928.     
  929.     Host_Init(&quakeparms);
  930.  
  931. //Sys_StackCheck ();
  932.  
  933. //Con_Printf ("Top of stack: 0x%x\n", &time);
  934.     oldtime = Sys_FloatTime ();
  935.     while (1)
  936.     {
  937.         newtime = Sys_FloatTime ();
  938.         time = newtime - oldtime;
  939.  
  940.         if (cls.state == ca_dedicated && (time<sys_ticrate.value))
  941.             continue;
  942.  
  943.         Host_Frame (time);
  944.  
  945. //Sys_StackCheck ();
  946.  
  947.         oldtime = newtime;
  948.     }
  949. }
  950.  
  951.  
  952.